home *** CD-ROM | disk | FTP | other *** search
/ PD Collection CD 1 / PD Collection CD 1.iso / textual / pdftops / xpdf / c++ / GfxState < prev    next >
Text File  |  1996-06-08  |  14KB  |  557 lines

  1. //========================================================================
  2. //
  3. // GfxState.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. //#pragma implementation
  11. #endif
  12.  
  13. #include <stddef.h>
  14. #include <math.h>
  15. #include <string.h> // for memcpy()
  16. #include "gmem.h"
  17. #include "Object.h"
  18. #include "GfxState.h"
  19.  
  20. //------------------------------------------------------------------------
  21. // GfxColor
  22. //------------------------------------------------------------------------
  23.  
  24. void GfxColor::setCMYK(double c, double m, double y, double k) {
  25.   if ((r = 1 - (c + k)) < 0)
  26.     r = 0;
  27.   if ((g = 1 - (m + k)) < 0)
  28.     g = 0;
  29.   if ((b = 1 - (y + k)) < 0)
  30.     b = 0;
  31. }
  32.  
  33. //------------------------------------------------------------------------
  34. // GfxColorSpace
  35. //------------------------------------------------------------------------
  36.  
  37. GfxColorSpace::GfxColorSpace(int bits1, Object *colorSpace, Object *decode) {
  38.   Object obj;
  39.   double decodeLow[4], decodeHigh[4];
  40.   int decodeComps;
  41.   Guchar (*palette)[4];
  42.   int indexHigh;
  43.   char *s;
  44.   int x;
  45.   int i, j, k;
  46.  
  47.   ok = gTrue;
  48.   bits = bits1;
  49.   lookup = NULL;
  50.   palette = NULL;
  51.  
  52.   // get decode map
  53.   if (decode->isNull()) {
  54.     decodeComps = 0;
  55.   } else if (decode->isArray()) {
  56.     decodeComps = decode->arrayGetLength() / 2;
  57.     for (i = 0; i < decodeComps; ++i) {
  58.       decode->arrayGet(2*i, &obj);
  59.       if (!obj.isNum())
  60.     goto err2;
  61.       decodeLow[i] = obj.getNum();
  62.       obj.free();
  63.       decode->arrayGet(2*i+1, &obj);
  64.       if (!obj.isNum())
  65.     goto err2;
  66.       decodeHigh[i] = obj.getNum();
  67.       obj.free();
  68.     }
  69.   } else {
  70.     goto err1;
  71.   }
  72.  
  73.   // get mode
  74.   indexed = gFalse;
  75.   if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) {
  76.     mode = colorGray;
  77.     numComponents = lookupComponents = 1;
  78.   } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) {
  79.     mode = colorRGB;
  80.     numComponents = lookupComponents = 3;
  81.   } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) {
  82.     mode = colorCMYK;
  83.     numComponents = lookupComponents = 4;
  84.   } else if (colorSpace->isArray()) {
  85.     colorSpace->arrayGet(0, &obj);
  86.     if (obj.isName("DeviceGray") || obj.isName("G")) {
  87.       mode = colorGray;
  88.       numComponents = lookupComponents = 1;
  89.     } else if (obj.isName("DeviceRGB") || obj.isName("RGB")) {
  90.       mode = colorRGB;
  91.       numComponents = lookupComponents = 3;
  92.     } else if (obj.isName("DeviceCMYK") || obj.isName("CMYK")) {
  93.       mode = colorCMYK;
  94.       numComponents = lookupComponents = 4;
  95.     } else if (obj.isName("Indexed") || obj.isName("I")) {
  96.       indexed = gTrue;
  97.       numComponents = 1;
  98.     } else {
  99.       goto err2;
  100.     }
  101.     obj.free();
  102.   }
  103.  
  104.   // indexed decoding
  105.   if (indexed) {
  106.     if (decodeComps == 0) {
  107.       decodeLow[0] = 0;
  108.       decodeHigh[0] = (1 << bits) - 1;
  109.     } else if (decodeComps != numComponents) {
  110.       goto err1;
  111.     }
  112.     colorSpace->arrayGet(1, &obj);
  113.     if (obj.isName("DeviceRGB") || obj.isName("RGB")) {
  114.       mode = colorRGB;
  115.       lookupComponents = 3;
  116.     } else if (obj.isName("DeviceCMYK") || obj.isName("CMYK")) {
  117.       mode = colorCMYK;
  118.       lookupComponents = 4;
  119.     } else {
  120.       goto err2;
  121.     }
  122.     obj.free();
  123.     colorSpace->arrayGet(2, &obj);
  124.     if (!obj.isInt())
  125.       goto err2;
  126.     indexHigh = obj.getInt();
  127.     obj.free();
  128.     palette = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar));
  129.     colorSpace->arrayGet(3, &obj);
  130.     if (obj.isStream()) {
  131.       obj.streamReset();
  132.       for (i = 0; i <= indexHigh; ++i) {
  133.     for (j = 0; j < lookupComponents; ++j) {
  134.       if ((x = obj.streamGetChar()) == EOF)
  135.         goto err3;
  136.       palette[i][j] = (Guchar)x;
  137.     }
  138.       }
  139.     } else if (obj.isString()) {
  140.       s = obj.getString()->getCString();
  141.       for (i = 0; i <= indexHigh; ++i)
  142.     for (j = 0; j < lookupComponents; ++j)
  143.       palette[i][j] = (Guchar)*s++;
  144.     } else {
  145.       goto err3;
  146.     }
  147.     obj.free();
  148.     lookup = (Guchar (*)[4])gmalloc((1 << bits) * 4 * sizeof(Guchar));
  149.     for (i = 0; i < (1 << bits); ++i) {
  150.       k = (int)(decodeLow[0] + i * (decodeHigh[0] - decodeLow[0]) /
  151.                                ((1 << bits) - 1) + 0.5);
  152.       switch (mode) {
  153.       case colorGray:
  154.     lookup[i][0] = lookup[i][1] = lookup[i][2] = palette[k][0];
  155.     break;
  156.       case colorCMYK:
  157.     x = palette[k][0] + palette[k][3];
  158.     lookup[i][0] = (x > 255) ? 0 : 255 - x;
  159.     x = palette[k][1] + palette[k][3];
  160.     lookup[i][1] = (x > 255) ? 0 : 255 - x;
  161.     x = palette[k][2] + palette[k][3];
  162.     lookup[i][2] = (x > 255) ? 0 : 255 - x;
  163.     break;
  164.       case colorRGB:
  165.     lookup[i][0] = palette[k][0];
  166.     lookup[i][1] = palette[k][1];
  167.     lookup[i][2] = palette[k][2];
  168.     break;
  169.       }
  170.     }
  171.     gfree(palette);
  172.  
  173.   // non-indexed decoding
  174.   } else {
  175.     if (decodeComps == 0) {
  176.       for (i = 0; i < numComponents; ++i) {
  177.     decodeLow[i] = 0;
  178.     decodeHigh[i] = 1;
  179.       }
  180.     } else if (decodeComps != numComponents) {
  181.       goto err1;
  182.     }
  183.     lookup = (Guchar (*)[4])gmalloc((1 << bits) * 4 * sizeof(Guchar));
  184.     for (i = 0; i < (1 << bits); ++i) {
  185.       for (j = 0; j < lookupComponents; ++j) {
  186.     lookup[i][j] = (Guchar)(255.0 * (decodeLow[j] +
  187.                      (double)i *
  188.                      (decodeHigh[j] - decodeLow[j]) /
  189.                      (double)((1 << bits) - 1)));
  190.       }
  191.     }
  192.   }
  193.  
  194.   return;
  195.  
  196.  err3:
  197.   gfree(palette);
  198.  err2:
  199.   obj.free();
  200.  err1:
  201.   ok = gFalse;
  202. }
  203.  
  204. GfxColorSpace::~GfxColorSpace() {
  205.   gfree(lookup);
  206. }
  207.  
  208. void GfxColorSpace::getGray(Guchar x[4], Guchar *gray) {
  209.   Guchar *p;
  210.  
  211.   if (indexed) {
  212.     p = lookup[x[0]];
  213.     *gray = (Guchar)(0.299 * p[0] + 0.587 * p[1] + 0.114 * p[2]);
  214.   } else {
  215.     switch (mode) {
  216.     case colorGray:
  217.       *gray = lookup[x[0]][0];
  218.       break;
  219.     case colorCMYK:
  220.       *gray = 255 - (Guchar)(lookup[x[3]][3] -
  221.                  0.299 * lookup[x[0]][0] -
  222.                  0.587 * lookup[x[1]][1] -
  223.                  0.114 * lookup[x[2]][2]);
  224.       break;
  225.     case colorRGB:
  226.       *gray = (Guchar)(0.299 * lookup[x[0]][0] +
  227.                0.587 * lookup[x[1]][1] +
  228.                0.114 * lookup[x[2]][2]);
  229.       break;
  230.     }
  231.   }
  232. }
  233.  
  234. void GfxColorSpace::getRGB(Guchar x[4], Guchar *r, Guchar *g, Guchar *b) {
  235.   Guchar *p;
  236.   int t;
  237.  
  238.   if (indexed) {
  239.     p = lookup[x[0]];
  240.     *r = p[0];
  241.     *g = p[1];
  242.     *b = p[2];
  243.   } else {
  244.     switch (mode) {
  245.     case colorGray:
  246.       *r = *g = *b = lookup[x[0]][0];
  247.       break;
  248.     case colorCMYK:
  249.       t = lookup[x[0]][0] + lookup[x[3]][3];
  250.       *r = (t > 255) ? 0 : 255 - t;
  251.       t = lookup[x[1]][1] + lookup[x[3]][3];
  252.       *g = (t > 255) ? 0 : 255 - t;
  253.       t = lookup[x[2]][2] + lookup[x[3]][3];
  254.       *b = (t > 255) ? 0 : 255 - t;
  255.       break;
  256.     case colorRGB:
  257.       *r = lookup[x[0]][0];
  258.       *g = lookup[x[1]][1];
  259.       *b = lookup[x[2]][2];
  260.       break;
  261.     }
  262.   }
  263. }
  264.  
  265. //------------------------------------------------------------------------
  266. // GfxSubpath and GfxPath
  267. //------------------------------------------------------------------------
  268.  
  269. GfxSubpath::GfxSubpath(double x1, double y1) {
  270.   size = 16;
  271.   x = (double *)gmalloc(size * sizeof(double));
  272.   y = (double *)gmalloc(size * sizeof(double));
  273.   n = 1;
  274.   x[0] = x1;
  275.   y[0] = y1;
  276. }
  277.  
  278. GfxSubpath::~GfxSubpath() {
  279.   gfree(x);
  280.   gfree(y);
  281. }
  282.  
  283. // Used for copy().
  284. GfxSubpath::GfxSubpath(double *x1, double *y1, int n1, int size1) {
  285.   size = size1;
  286.   n = n1;
  287.   x = (double *)gmalloc(size * sizeof(double));
  288.   y = (double *)gmalloc(size * sizeof(double));
  289.   memcpy(x, x1, n * sizeof(double));
  290.   memcpy(y, y1, n * sizeof(double));
  291. }
  292.  
  293. void GfxSubpath::lineTo(double x1, double y1) {
  294.   if (n >= size) {
  295.     size += 16;
  296.     x = (double *)grealloc(x, size * sizeof(double));
  297.     y = (double *)grealloc(y, size * sizeof(double));
  298.   }
  299.   x[n] = x1;
  300.   y[n] = y1;
  301.   ++n;
  302. }
  303.  
  304. GfxPath::GfxPath() {
  305.   size = 16;
  306.   n = 0;
  307.   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
  308. }
  309.  
  310. GfxPath::~GfxPath() {
  311.   int i;
  312.  
  313.   for (i = 0; i < n; ++i)
  314.     delete subpaths[i];
  315.   gfree(subpaths);
  316. }
  317.  
  318. // Used for copy().
  319. GfxPath::GfxPath(GfxSubpath **subpaths1, int n1, int size1) {
  320.   int i;
  321.  
  322.   size = size1;
  323.   n = n1;
  324.   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
  325.   for (i = 0; i < n; ++i)
  326.     subpaths[i] = subpaths1[i]->copy();
  327. }
  328.  
  329. void GfxPath::moveTo(double x, double y) {
  330.   if (n >= size) {
  331.     size += 16;
  332.     subpaths = (GfxSubpath **)grealloc(subpaths, size * sizeof(GfxSubpath *));
  333.   }
  334.   subpaths[n] = new GfxSubpath(x, y);
  335.   ++n;
  336. }
  337.  
  338. //------------------------------------------------------------------------
  339. // GfxState
  340. //------------------------------------------------------------------------
  341.  
  342. GfxState::GfxState(int dpi, int x1, int y1, int x2, int y2, int rotate,
  343.            GBool upsideDown) {
  344.   double k;
  345.  
  346.   k = (double)dpi / 72.0;
  347.   if (rotate == 90) {
  348.     ctm[0] = 0;
  349.     ctm[1] = upsideDown ? k : -k;
  350.     ctm[2] = k;
  351.     ctm[3] = 0;
  352.     ctm[4] = -k * y1;
  353.     ctm[5] = k * (upsideDown ? -x1 : x2);
  354.     pageWidth = (int)(k * (y2 - y1));
  355.     pageHeight = (int)(k * (x2 - x1));
  356.   } else if (rotate == 180) {
  357.     ctm[0] = -k;
  358.     ctm[1] = 0;
  359.     ctm[2] = 0;
  360.     ctm[3] = upsideDown ? k : -k;
  361.     ctm[4] = k * x2;
  362.     ctm[5] = k * (upsideDown ? -y1 : y2);
  363.     pageWidth = (int)(k * (x2 - x1));
  364.     pageHeight = (int)(k * (y2 - y1));
  365.   } else if (rotate == 270) {
  366.     ctm[0] = 0;
  367.     ctm[1] = upsideDown ? -k : k;
  368.     ctm[2] = -k;
  369.     ctm[3] = 0;
  370.     ctm[4] = k * y2;
  371.     ctm[5] = k * (upsideDown ? x2 : -x1);
  372.     pageWidth = (int)(k * (y2 - y1));
  373.     pageHeight = (int)(k * (x2 - x1));
  374.   } else {
  375.     ctm[0] = k;
  376.     ctm[1] = 0;
  377.     ctm[2] = 0;
  378.     ctm[3] = upsideDown ? -k : k;
  379.     ctm[4] = -k * x1;
  380.     ctm[5] = k * (upsideDown ? y2 : -y1);
  381.     pageWidth = (int)(k * (x2 - x1));
  382.     pageHeight = (int)(k * (y2 - y1));
  383.   }
  384.  
  385.   fillColor.setGray(0);
  386.   strokeColor.setGray(0);
  387.  
  388.   lineWidth = 1;
  389.   lineDash = NULL;
  390.   lineDashLength = 0;
  391.   lineDashStart = 0;
  392.   flatness = 0;
  393.   lineJoin = 0;
  394.   lineCap = 0;
  395.   miterLimit = 10;
  396.  
  397.   font = NULL;
  398.   fontSize = 0;
  399.   textMat[0] = 1; textMat[1] = 0;
  400.   textMat[2] = 0; textMat[3] = 1;
  401.   textMat[4] = 0; textMat[5] = 0;
  402.   charSpace = 0;
  403.   wordSpace = 0;
  404.   horizScaling = 100;
  405.   leading = 0;
  406.   rise = 0;
  407.   render = 0;
  408.  
  409.   path = new GfxPath();
  410.   curX = curY = 0;
  411.   lineX = lineY = 0;
  412.  
  413.   saved = NULL;
  414. }
  415.  
  416. GfxState::~GfxState() {
  417.   gfree(lineDash);
  418.   delete path;
  419.   if (saved)
  420.     delete saved;
  421. }
  422.  
  423. // Used for copy();
  424. GfxState::GfxState(GfxState *state) {
  425.   memcpy(this, state, sizeof(GfxState));
  426.   if (lineDashLength > 0) {
  427.     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
  428.     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
  429.   }
  430.   path = state->path->copy();
  431.   saved = NULL;
  432. }
  433.  
  434. double GfxState::transformWidth(double w) {
  435.   double x, y;
  436.  
  437.   x = ctm[0] + ctm[2];
  438.   y = ctm[1] + ctm[3];
  439.   return w * sqrt(0.5 * (x * x + y * y));
  440. }
  441.  
  442. double GfxState::getTransformedFontSize() {
  443.   double x1, y1, x2, y2;
  444.  
  445.   x1 = textMat[2] * fontSize;
  446.   y1 = textMat[3] * fontSize;
  447.   x2 = ctm[0] * x1 + ctm[2] * y1;
  448.   y2 = ctm[1] * x1 + ctm[3] * y1;
  449.   return sqrt(x2 * x2 + y2 * y2);
  450. }
  451.  
  452. void GfxState::getFontTransMat(double *m11, double *m12,
  453.                    double *m21, double *m22) {
  454.   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
  455.   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
  456.   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
  457.   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
  458. }
  459.  
  460. void GfxState::concatCTM(double a, double b, double c,
  461.              double d, double e, double f) {
  462.   double a1 = ctm[0];
  463.   double b1 = ctm[1];
  464.   double c1 = ctm[2];
  465.   double d1 = ctm[3];
  466.  
  467.   ctm[0] = a * a1 + b * c1;
  468.   ctm[1] = a * b1 + b * d1;
  469.   ctm[2] = c * a1 + d * c1;
  470.   ctm[3] = c * b1 + d * d1;
  471.   ctm[4] = e * a1 + f * c1 + ctm[4];
  472.   ctm[5] = e * b1 + f * d1 + ctm[5];
  473. }
  474.  
  475. void GfxState::setLineDash(double *dash, int length, double start) {
  476.   if (lineDash)
  477.     gfree(lineDash);
  478.   lineDash = dash;
  479.   lineDashLength = length;
  480.   lineDashStart = start;
  481. }
  482.  
  483. void GfxState::curveTo(double x1, double y1, double x2, double y2,
  484.                double x3, double y3) {
  485.   doCurveTo(curX, curY, x1, y1, x2, y2, x3, y3, 0);
  486. }
  487.  
  488. void GfxState::doCurveTo(double x0, double y0, double x1, double y1,
  489.              double x2, double y2, double x3, double y3,
  490.              int splits) {
  491.   double x4, y4, dx, dy;
  492.   double xl0, yl0, xl1, yl1, xl2, yl2, xl3, yl3;
  493.   double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
  494.   double xh, yh;
  495.  
  496.   x4 = 0.125 * (x0 + 3 * (x1 + x2) + x3);
  497.   y4 = 0.125 * (y0 + 3 * (y1 + y2) + y3);
  498.   dx = x4 - (x0 + x3) / 2;
  499.   dy = y4 - (y0 + y3) / 2;
  500.   if (dx*dx + dy*dy <= 0.1 || splits > 8) {
  501.     lineTo(x3, y3);
  502.   } else {
  503.     xl0 = x0;
  504.     yl0 = y0;
  505.     xl1 = (x0 + x1) / 2;
  506.     yl1 = (y0 + y1) / 2;
  507.     xh = (x1 + x2) / 2;
  508.     yh = (y1 + y2) / 2;
  509.     xl2 = (xl1 + xh) / 2;
  510.     yl2 = (yl1 + yh) / 2;
  511.     xr3 = x3;
  512.     yr3 = y3;
  513.     xr2 = (x2 + x3) / 2;
  514.     yr2 = (y2 + y3) / 2;
  515.     xr1 = (xh + xr2) / 2;
  516.     yr1 = (yh + yr2) / 2;
  517.     xl3 = xr0 = (xl2 + xr1) / 2;
  518.     yl3 = yr0 = (yl2 + yr1) / 2;
  519.     doCurveTo(xl0, yl0, xl1, yl1, xl2, yl2, xl3, yl3, splits + 1);
  520.     doCurveTo(xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3, splits + 1);
  521.   }
  522. }
  523.  
  524. void GfxState::clearPath() {
  525.   delete path;
  526.   path = new GfxPath();
  527. }
  528.  
  529. void GfxState::textShift(double tx) {
  530.   double dx, dy;
  531.  
  532.   textTransformDelta(tx, 0, &dx, &dy);
  533.   curX += dx;
  534.   curY += dy;
  535. }
  536.  
  537. GfxState *GfxState::save() {
  538.   GfxState *newState;
  539.  
  540.   newState = copy();
  541.   newState->saved = this;
  542.   return newState;
  543. }
  544.  
  545. GfxState *GfxState::restore() {
  546.   GfxState *oldState;
  547.  
  548.   if (saved) {
  549.     oldState = saved;
  550.     saved = NULL;
  551.     delete this;
  552.   } else {
  553.     oldState = this;
  554.   }
  555.   return oldState;
  556. }
  557.